package br.ufpe.cin.mac.middleware.autonomic;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import br.ufpe.cin.mac.middleware.autonomic.monitors.Monitor;
import br.ufpe.cin.mac.middleware.autonomic.rules.AutonomicBase;
import br.ufpe.cin.mac.middleware.components.ConcreteComponent;
import br.ufpe.cin.mac.util.Constants;
import br.ufpe.cin.mac.util.Message;

public class Checker extends ConcreteComponent implements CheckerMBean {

	private Map<String, Monitor> monitors;

	private KnowledgeBase kb;

	private List<String> interceptors;

	public Checker(KnowledgeBase kb) {
		super(Checker.class.getName());
		monitors = new HashMap<String, Monitor>();
		this.kb = kb;
		System.out.println("KnowledgeBase size: "
				+ kb.getTransitions().size());
		new Thread() {
			public void run() {
				try {
					
					while (true) {
						Thread.sleep(5000);
						getInterceptors();
						Thread.sleep(500);
						// System.err.println("### " + interceptors);

						readMonitors();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}.start();
	}

	public void addMonitor(String name, Monitor monitor) {
		if (monitor != null) {
			this.monitors.put(name, monitor);
		}
	}

	private void readMonitors() {

		// getInterceptors();
		Config config = createConfig();

		AutonomicBase at = new AutonomicBase();
		at.insert(config);
		at.insert(this);
		at.insert(kb);

		at.run();
	}

	private List<String> getInterceptors() {
		Message msg = new Message();
		msg.setSender(Constants.COMP_CHECKER);
		msg.setMethod(Constants.METH_GET_INTERCEPTORS);
		msg.setType(Constants.ACTION_CHECKER);

		buffer.put(msg.hashCode(), msg);
		sendNotification(msg, "terP");
		return null;
	}

	public void changeConfiguration(final Config config, final String rule,
			String oldInterceptor, String newInterceptor) {
		if (!config.contaisInterceptor(newInterceptor)) {
			System.out.println("Old " + oldInterceptor);
			System.out.println("New " + newInterceptor);
			Message msg = new Message();

			msg.setType(Constants.ACTION_CHECKER);
			msg.setParameter(new String[] { oldInterceptor, newInterceptor });
			msg.setMethod(Constants.METH_CHANGEINTERCEPTOR);

			buffer.put(msg.hashCode(), msg);
			sendNotification(msg, "terP");

			new Thread() {
				public void run() {
					try {
						Thread.sleep(10000);
						addTransition(config, rule);
					} catch (Exception e) {
					}
				}
			}.start();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void msgManager(Message msg) {
		if (msg.getMethod().equals(Constants.METH_GET_INTERCEPTORS)) {
			this.interceptors = (List<String>) msg.getParameter()[0];
		}
	}

	private void addTransition(Config oldConfig, String rule) {
		Config newConfig = createConfig();
		Transition t = new Transition(oldConfig, newConfig, rule);
		kb.addTransition(t);
		System.out.println("KnowledgeBase size: " + kb.getTransitions().size());
	}

	private Config createConfig() {
		Config config = new Config();
		Set<String> monitorsKey = this.monitors.keySet();
		Iterator<String> it = monitorsKey.iterator();

		Calendar cal = Calendar.getInstance();

		cal.setTimeInMillis(System.currentTimeMillis());
		config.setInterceptors(this.interceptors);
		config.setCalendar(cal);

		String monName;
		Monitor monitor;
		while (it.hasNext()) {
			monName = it.next();
			monitor = this.monitors.get(monName);
			float value = monitor.getMonitoredValue();
			System.out.println("##### " + monName + " " + value);
			config.putValue(monName, value);
		}
		return config;
	}

	public static void main(String args[]) {

		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(System.currentTimeMillis());
		System.out.println(cal.getTime());

		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		cal.setTimeInMillis(System.currentTimeMillis());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		cal.setTimeInMillis(System.currentTimeMillis());
		System.out.println(cal.getTime());
		System.out.println(cal.getTime());
		// KnowledgeBase kb = Loader.loadKnowledgeBase();
		// Checker checker = new Checker(kb);
		// checker.teste();

	}
}
